import { animation, AnimationClip, Sprite, SpriteFrame } from "cc";
import ResourceManager from "../Runtime/ResourceManager";
import StateMachine from "./StateMachine";
import { sortSpriteFrame } from "../Utils";

export const ANIMATION_SPEED = 1 / 8

/*
1. 需要知道 animationClip
2. 需要播放动画的能力 animation
*/
export default class State {
    private animationClip: AnimationClip
    constructor(
        private fsm: StateMachine,
        private path: string,
        private wrapMode: AnimationClip.WrapMode = AnimationClip.WrapMode.Normal,
        private speed: number = ANIMATION_SPEED,
        private events: Array<AnimationClip.IEvent> = [],
    ) {
        this.init()
    }

    async init() {
        const promise = ResourceManager.Instance.loadDir(this.path)
        this.fsm.waitingList.push(promise)

        const spriteFrames = await promise

        // console.log('加载的精灵帧:', this.path, spriteFrames)

        // 程序化编辑动画剪辑： https://docs.cocos.com/creator/3.8/manual/zh/animation/use-animation-curve.html
        this.animationClip = new AnimationClip()

        const track = new animation.ObjectTrack()
        track.path = new animation.TrackPath().toComponent(Sprite).toProperty('spriteFrame')
        const frames: Array<[number, SpriteFrame]> = sortSpriteFrame(spriteFrames).map((item, index) => [this.speed * index, item])
        track.channel.curve.assignSorted(frames)

        // 最后将轨道添加到动画剪辑以应用
        this.animationClip.addTrack(track)
        this.animationClip.name = this.path
        this.animationClip.duration = frames.length * this.speed // 整个动画剪辑的周期
        this.animationClip.wrapMode = this.wrapMode

        // 帧事件监听：https://docs.cocos.com/creator/3.8/manual/zh/animation/animation-component.html#%E5%B8%A7%E4%BA%8B%E4%BB%B6
        for (const event of this.events) {
            this.animationClip.events.push(event)
        }
        this.animationClip.updateEventDatas()
    }

    run() {
        // 如果当前正在播放的动画和将要播放的动画相同，就不播放
        if (this.fsm.animationComponent?.defaultClip?.name === this.animationClip.name) {
            return
        }
        this.fsm.animationComponent.defaultClip = this.animationClip
        this.fsm.animationComponent.play()
    }
}
